package com.lingjtx.common.core;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 常用redis命令操作，key（redis key 和 HashKey）统一为String类型，value 为Object任意对象
 * value 采用Jackson2JsonRedisSerializer序列化存储
 */
public interface RedisOptions {

    // 说明：对于key的操作都用基本类型作为返回值，但是对应redis数据类型操作时返回类型用基本类型包装对象
    // 因为当你操作一个key是其他redis数据类型的时候会有异常返回，这样可以返回null

    //—————————————————————————— key 的操作 ——————————————————————————

    // 删除已存在的键。不存在的 key 会被忽略
    boolean delete(String key);

    // 批量删除keys
    void delete(String... keys);

    /**
     * 删除正则匹配的keys
     *
     * @param pattern
     */
    void deletePattern(String pattern);

    // 检查给定 key 是否存在
    boolean exists(String key);

    /**
     * 设置 key 的过期时间，key 过期后将不再可用
     *
     * @param key     key
     * @param timeout 多长过期
     * @param unit    单位
     * @return
     */
    boolean expire(String key, long timeout, TimeUnit unit);

    // timeout单位秒
    boolean expire(String key, long timeout);

    /**
     * 获取过期时间 ttl命令
     */
    Long getExpire(String key);

    Long getExpire(String key, TimeUnit timeUnit);

    /**
     * 设置 key 的过期时间
     *
     * @param key  key
     * @param date 过期日期时间
     * @return
     */
    boolean expireAt(String key, Date date);

    // 根据正则表达式查询匹配的keys
    Set<String> keys(String pattern);

    // 移除给定 key 的过期时间，使得 key 永不过期
    boolean persist(String key);

    // 从当前数据库中随机返回一个 key
    String randomKey();

    // 修改 key 的名称，
    // 当 OLD_KEY_NAME 和 NEW_KEY_NAME 相同，或者 OLD_KEY_NAME 不存在时，返回一个错误。
    // 当 NEW_KEY_NAME 已经存在时， RENAME 命令将覆盖旧值
    void rename(String oldKey, String newKey);

    // 新的 key 不存在时修改 key 的名称
    boolean renameIfAbsent(String oldKey, String newKey);

    // 用于序列化给定 key ，并返回被序列化的值
    byte[] dump(String key);

    // —————————————————————————————— String 类型操作——————————————————————————————

    void set(String key, Object value);

    /**
     * @param key     key
     * @param value   存储值
     * @param timeout 多长时间过期
     * @param unit    时间单位
     */
    void set(String key, Object value, long timeout, TimeUnit unit);

    // timeout单位秒
    void set(String key, Object value, long timeout);

    // Redis Setnx（SET if Not eXists） 命令在指定的 key 不存在时，为 key 设置指定的值
    Boolean setIfAbsent(String key, Object value);

    Boolean setIfAbsent(String key, Object value, long timeout, TimeUnit unit);

    Boolean setIfAbsent(String key, Object value, long timeout);

    // Redis Get 命令用于获取指定 key 的值。如果 key 不存在，返回 nil 。如果key 储存的值不是字符串类型，返回一个错误
    Object get(String key);

    /**
     * Redis Getset 命令用于设置指定 key 的值，并返回 key 的旧值
     * 返回给定 key 的旧值。 当 key 没有旧值时，即 key 不存在时，返回 nil
     * 当 key 存在但不是字符串类型时，返回一个错误。
     */
    Object getAndSet(String key, Object value);

    /**
     * Redis Mget 命令返回所有(一个或多个)给定 key 的值。 如果给定的 key 里面，有某个 key 不存在，那么这个 key 返回特殊值 nil 。
     */
    List<Object> multiGet(String... keys);

    /**
     * Redis Incr 命令将 key 中储存的数字值增一。
     * 如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 INCR 操作。
     * 如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回null
     *
     * @param key
     * @return 本操作的值限制在 64 位(bit)有符号数字表示之内
     */
    Long increment(String key);

    // 将 key 中储存的数字加上指定(delta)的增量值
    Long increment(String key, long delta);

    /**
     * Redis Incrbyfloat 命令为 key 中所储存的值加上指定的浮点数增量值。
     * 如果 key 不存在，那么 INCRBYFLOAT 会先将 key 的值设为 0 ，再执行加法操作
     *
     * @param key
     * @param delta
     * @return
     */
    Double increment(String key, double delta);

    // 将 key 中储存的数字值减一
    Long decrement(String key);

    /**
     * 将 key 中储存的数字减去指定(delta)的值
     *
     * @param key
     * @param delta
     * @return 返回减去之后的值
     */
    Long decrement(String key, long delta);

    /**
     * Redis Append 命令用于为指定的 key 追加值。
     * 如果 key 已经存在并且是一个字符串， APPEND 命令将 value 追加到 key 原来的值的末尾。
     * 如果 key 不存在， APPEND 就简单地将给定 key 设为 value ，就像执行 SET key value 一样
     *
     * @param key
     * @param value
     * @return 追加指定值之后， key 中字符串的长度
     */
    Integer append(String key, String value);

    // Redis Strlen 命令用于获取指定 key 所储存的字符串值的长度。当 key 储存的不是字符串值时，返回null
    Long size(String key);

    // ————————————————————————————————————哈希(Hash)——————————————————————————————————————

    Long hmDelete(String key, String... hashKeys);

    Boolean hmExists(String key, String hashKey);

    Object hmGet(String key, String hashKey);

    List<Object> hmMultiGet(String key, Collection<String> hashKeys);

    List<Object> hmMultiGet(String key, String... hashKeys);

    Long hmIncrement(String key, String hashKey, long delta);

    Double hmIncrement(String key, String hashKey, double delta);

    Long hmSize(String key);

    void hmPutAll(String key, Map<String, Object> m);

    void hmPut(String key, String hashKey, Object value);

    Boolean hmPutIfAbsent(String key, String hashKey, Object value);

    Set<String> hmKeys(String key);

    // 获取map对象中所有values
    List<Object> hmValues(String key);

    // 获取Map对象
    Map<String, Object> hmEntries(String key);

    // ———————————————————————————————————— 列表(List) ——————————————————————————————————————-

    List<Object> lRange(String key, long start, long end);

    void lTrim(String key, long start, long end);

    Long lSize(String key);

    // 在列表第一个元素前插入 value
    Long leftPush(String key, Object value);

    Long leftPushAll(String key, Collection<Object> values);

    Long leftPushAll(String key, Object... values);

    Long leftPushIfPresent(String key, Object value);

    // 在 pivot 元素之前插入 value
    Long leftInsert(String key, Object pivot, Object value);

    // 向列表中插入元素 value
    Long rightPush(String key, Object value);

    Long rightPushAll(String key, Object... values);

    Long rightPushAll(String key, Collection<Object> values);

    Long rightPushIfPresent(String key, Object value);

    // 在 pivot 元素之后插入 value
    Long rightInsert(String key, Object pivot, Object value);

    void lSet(String key, long index, Object value);

    /**
     * Redis Lrem 根据参数 COUNT 的值，移除列表中与参数 VALUE 相等的元素。
     * COUNT 的值可以是以下几种：
     * count > 0 : 从表头开始向表尾搜索，移除与 VALUE 相等的元素，数量为 COUNT 。
     * count < 0 : 从表尾开始向表头搜索，移除与 VALUE 相等的元素，数量为 COUNT 的绝对值。
     * count = 0 : 移除表中所有与 VALUE 相等的值。
     *
     * @param key
     * @param count
     * @param value
     * @return
     */
    Long lRemove(String key, long count, Object value);

    Object lIndex(String key, long index);

    // Redis lPop 命令用于移除并返回列表的第一个元素。
    Object leftPop(String key);

    Object leftPop(String key, long timeout, TimeUnit unit);

    Object leftPop(String key, long timeout);

    // Redis Rpop 命令用于移除列表的最后一个元素，返回值为移除的元素。
    Object rightPop(String key);

    Object rightPop(String key, long timeout, TimeUnit unit);

    Object rightPop(String key, long timeout);

    // Redis Rpoplpush 命令用于移除列表的最后一个元素，并将该元素添加到另一个列表并返回。
    Object rightPopAndLeftPush(String sourceKey, String destinationKey);

    // ————————————————————————————————————— 集合(Set) ——————————————————————————————-

    Long sAdd(String key, Object... values);

    Long sRemove(String key, Object... values);

    // Redis Spop 命令用于移除集合中第一个元素，移除后会返回移除的元素
    Object sPop(String key);

    // Redis Spop 命令用于移除集合中的指定 key 的一个或多个随机元素，移除后会返回移除的元素
    List<Object> sPop(String key, long count);

    /**
     * Redis Smove 命令将指定成员 member 元素从 source 集合移动到 destination 集合。
     * SMOVE 是原子性操作。
     * 如果 source 集合不存在或不包含指定的 member 元素，则 SMOVE 命令不执行任何操作，仅返回 0 。否则， member 元素从 source 集合中被移除，并添加到 destination 集合中去。
     * 当 destination 集合已经包含 member 元素时， SMOVE 命令只是简单地将 source 集合中的 member 元素删除。
     * 当 source 或 destination 不是集合类型时，返回null。
     * SMOVE SOURCE DESTINATION MEMBER
     */
    Boolean sMove(String srcKey, Object member, String destKey);

    Long sSize(String key);

    Boolean sIsMember(String key, Object value);

    // Redis Sinter 命令返回给定所有给定集合的交集。 不存在的集合 key 被视为空集。 当给定集合当中有一个空集时，结果也为空集(根据集合运算定律)。
    Set<Object> sIntersect(String key, String otherKey);

    Set<Object> sIntersect(String key, Collection<String> otherKeys);

    // Redis Sinterstore 命令将给定集合之间的交集存储在指定的集合中。如果指定的集合已经存在，则将其覆盖。
    // SINTERSTORE DESTINATION_KEY KEY KEY1..KEYN
    Long sIntersectAndStore(String key, String otherKey, String destKey);

    Long sIntersectAndStore(String key, Collection<String> otherKeys, String destKey);

    // Sunion 命令返回给定集合的并集。不存在的集合 key 被视为空集。
    Set<Object> sUnion(String key, String otherKey);

    // Redis Sunion 命令返回给定集合的并集。不存在的集合 key 被视为空集。
    Set<Object> sUnion(String key, Collection<String> collection);

    // Redis Sunionstore 命令将给定集合的并集存储在指定的集合 destination 中。如果 destination 已经存在，则将其覆盖。
    // SUNIONSTORE destination key [key ...]
    Long sUnionAndStore(String key, String otherKey, String destKey);

    Long sUnionAndStore(String key, Collection<String> otherKeys, String destKey);

    //Redis Sdiff 命令返回第一个集合与其他集合之间的差异，也可以认为说第一个集合中独有的元素。不存在的集合 key 将视为空集。
    //差集的结果来自前面的 FIRST_KEY ,而不是后面的 OTHER_KEY1，也不是整个 FIRST_KEY OTHER_KEY1..OTHER_KEYN 的差集。
    // SDIFF FIRST_KEY OTHER_KEY1..OTHER_KEYN
    Set<Object> sDifference(String key, String otherKey);

    Set<Object> sDifference(String var1, Collection<String> otherKeys);

    // Redis Sdiffstore 命令将给定集合之间的差集存储在指定的集合中。如果指定的集合 key 已存在，则会被覆盖。
    Long sDifferenceAndStore(String key, String otherKey, String destKey);

    Long sDifferenceAndStore(String key, Collection<String> otherKeys, String destKey);

    Set<Object> sMembers(String key);

    // Redis Srandmember 命令用于返回集合中的一个随机元素。
    Object sRandomMember(String key);

    /**
     * Redis Srandmember 命令用于返回集合中的一个随机元素。
     * 从 Redis 2.6 版本开始， Srandmember 命令接受可选的 count 参数：
     * 如果 count 为正数，且小于集合基数，那么命令返回一个包含 count 个元素的数组，数组中的元素各不相同。如果 count 大于等于集合基数，那么返回整个集合。
     * 如果 count 为负数，那么命令返回一个数组，数组中的元素可能会重复出现多次，而数组的长度为 count 的绝对值。
     * 该操作和 SPOP 相似，但 SPOP 将随机元素从集合中移除并返回，而 Srandmember 则仅仅返回随机元素，而不对集合进行任何改动
     */
    Set<Object> sDistinctRandomMembers(String key, long count);

    // 返回一个或多个随机元素
    List<Object> sRandomMembers(String key, long count);

    // ————————————————————————————————————————有序集合(sorted set)————————————————————————————————————————
    // Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。
    //不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。
    //有序集合的成员是唯一的,但分数(score)却可以重复。
    //集合是通过哈希表实现的，所以添加，删除，查找的复杂度都是 O(1)。 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。

    Boolean zAdd(String key, Object value, double score);

    Long zRemove(String key, Object... values);

    /**
     * Redis Zincrby 命令对有序集合中指定成员的分数加上增量 delta
     * 可以通过传递一个负数值 delta ，让分数减去相应的值，比如 ZINCRBY key -5 member ，就是让 member 的 score 值减去 5 。
     * 当 key 不存在，或分数不是 key 的成员时， ZINCRBY key increment member 等同于 ZADD key increment member 。
     * 当 key 不是有序集类型时，返回一个错误。
     * 分数值可以是整数值或双精度浮点数。
     *
     * @param key
     * @param value
     * @param delta increment增量
     * @return
     */
    Double zIncrementScore(String key, Object value, double delta);

    /**
     * Redis Zrank 返回有序集中指定成员的排名。其中有序集成员按分数值递增(从小到大)顺序排列。
     *
     * @param key
     * @param value
     * @return 如果成员是有序集 key 的成员，返回 member 的排名。 如果成员不是有序集 key 的成员，返回 nil
     */
    Long zRank(String key, Object value);

    /**
     * Redis Zrevrank 命令返回有序集中成员的排名。其中有序集成员按分数值递减(从大到小)排序
     * 排名以 0 为底，也就是说， 分数值最大的成员排名为 0
     * 使用 ZRANK 命令可以获得成员按分数值递增(从小到大)排列的排名。
     *
     * @param key
     * @param value
     * @return 如果成员是有序集 key 的成员，返回成员的排名。 如果成员不是有序集 key 的成员，返回 nil
     */
    Long zReverseRank(String key, Object value);

    /**
     * Redis Zrange 返回有序集中，指定区间内的成员。
     * ZRANGE key start stop [WITHSCORES]
     * 其中成员的位置按分数值递增(从小到大)来排序。
     * 具有相同分数值的成员按字典序(lexicographical order )来排列。
     * 如果你需要成员按
     * 值递减(从大到小)来排列，请使用 ZREVRANGE 命令。
     * 下标参数 start 和 stop 都以 0 为底，也就是说，以 0 表示有序集第一个成员，以 1 表示有序集第二个成员，以此类推。
     * 你也可以使用负数下标，以 -1 表示最后一个成员， -2 表示倒数第二个成员，以此类推。
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    Set<Object> zRange(String key, long start, long end);


    /**
     * Redis Zrangebyscore 返回有序集合中指定分数区间的成员列表。有序集成员按分数值递增(从小到大)次序排列。
     * ZRANGEBYSCORE zset (1 5 返回所有符合条件 1 < score <= 5 的成员，而
     * 具有相同分数值的成员按字典序来排列(该属性是有序集提供的，不需要额外的计算)。
     * 默认情况下，区间的取值使用闭区间 (小于等于或大于等于)，你也可以通过给参数前增加 ( 符号来使用可选的开区间 (小于或大于)。
     *
     * @return 指定区间内，带有分数值(可选)的有序集成员的列表。
     */
    Set<Object> zRangeByScore(String key, double min, double max);

    Set<Object> zRangeByScore(String key, double min, double max, long offset, long count);

    /**
     * Redis Zrevrange 命令返回有序集中，指定区间内的成员。
     * 其中成员的位置按分数值递减(从大到小)来排列。
     * 具有相同分数值的成员按字典序的逆序(reverse lexicographical order)排列。
     * 除了成员按分数值递减的次序排列这一点外， ZREVRANGE 命令的其他方面和 ZRANGE 命令一样。
     *
     * @param key
     * @param start
     * @param end
     * @return 指定区间内，带有分数值(可选)的有序集成员的列表。
     */
    Set<Object> zReverseRange(String key, long start, long end);


    Set<Object> zReverseRangeByScore(String key, double min, double max);


    Set<Object> zReverseRangeByScore(String key, double min, double max, long offset, long count);


    /**
     * Redis Zcount 命令用于计算有序集合中指定分数区间的成员数量。
     * ZCOUNT key min max
     *
     * @param key
     * @param min
     * @param max
     * @return 分数值在 min 和 max 之间的成员的数量。
     */
    Long zCount(String key, double min, double max);


    Long zSize(String key);

    /**
     * Redis Zcard 命令用于计算集合中元素的数量。
     *
     * @param key
     * @return 当 key 存在且是有序集类型时，返回有序集的基数。 当 key 不存在时，返回 0 。
     */
    Long zCard(String key);


    Double zScore(String key, Object value);

    // 移除指定区间的成员
    Long zRemoveRange(String key, long start, long end);

    /**
     * Redis Zremrangebyscore 命令用于移除有序集中，指定分数（score）区间内的所有成员。
     *
     * @param key
     * @param min
     * @param max
     * @return 被移除成员的数量。
     */
    Long zRemoveRangeByScore(String key, double min, double max);

    /**
     * Redis Zunionstore 命令计算给定的一个或多个有序集的并集，其中给定 key 的数量必须以 numkeys 参数指定，并将该并集(结果集)储存到 destination 。
     * 默认情况下，结果集中某个成员的分数值是所有给定集下该成员分数值之和 。
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return 保存到 destination 的结果集的成员数量
     */
    Long zUnionAndStore(String key, String otherKey, String destKey);


    Long zUnionAndStore(String key, Collection<String> otherKeys, String destKey);

    /**
     * Redis Zinterstore 命令计算给定的一个或多个有序集的交集，其中给定 key 的数量必须以 numkeys 参数指定，并将该交集(结果集)储存到 destination 。
     * ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
     * 默认情况下，结果集中某个成员的分数值是所有给定集下该成员分数值之和。
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return 保存到目标结果集的的成员数量。
     */
    Long zIntersectAndStore(String key, String otherKey, String destKey);


    Long zIntersectAndStore(String key, Collection<String> otherKeys, String destKey);
}
